#include <stringprep.h>
#include <stddef.h>
#include <gcrypt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include "Ice.h"
#include "common/Mutex.h"

Mutex gIceMutex;

//#define DEFAULT_PRINT_PATH "/tmp/IceLog.log"
void Printf(char* filePath, const char *out, ...)
{
        /*
	char printf_buf[1024];
	va_list args;
	int printed;
	FILE *fp;
	if(filePath == NULL)
		fp = fopen(DEFAULT_PRINT_PATH,"a+");
	else 
		fp = fopen(filePath, "a+");
    if (fp != NULL) {
		va_start(args, out);
		printed = vsprintf(printf_buf, out, args);
		va_end(args);
		fseek(fp,SEEK_SET,SEEK_END);
		fputs(printf_buf, fp);
		fclose(fp);
	}
	return;
        */              
}

void StunLogBlock(char *filePath, unsigned char *buf, int len, const char *vname)
{
	int i = 0;
	
	Printf(filePath, "%s content:\r\n", vname);
	for(i=0; i<len; i++)
	{
		if(i%8==0 && i!=0)
			Printf(filePath, "\r\n");
		Printf(filePath, "%02x ", buf[i]);
	}
	Printf(filePath, "\r\n");
}

#define SET_POINTER_VALUE(p, len1, ptype, ptypefuc, value, len2)\
	do{\
		Printf(NULL, "%s value = 0x%x\r\n", #value,value);\
		*(ptype p) = ptypefuc(value);\
		p += len2;\
		len1 += len2;\
		}while(0)

#define SET_POINTER_BLOCK_VALUE(p, len1, pValue, len2 )\
	do{\
		StunLogBlock(NULL, (unsigned char *)pValue, len2, #pValue);\
		memcpy(p, pValue, len2);\
		p += len2;\
		len1 += len2;\
		}while(0)

#define AddIcePadding(offset, len, ptail)\
	do{\
		while(offset > 0 && offset < ICE_ATTRI_SLIDE)\
		{\
			SET_POINTER_VALUE(ptail, len, (unsigned char *), (unsigned char), 0, sizeof(char));\
			offset--;\
		}\
	}while(0)

#define ICE_SET_ERROR_CODE(value, dest)\
	if((dest) != NULL)\
	{\
		*(dest) = (value);\
	}\


#define IsatofChar(value) (value>='a' && value<='f')
#define IsAtoFChar(value) (value>='A' && value<='F')
#define Is0to9Char(value) (value>='0' && value<='9')
#define IsValidIpNumChar(value) ( IsatofChar(value) || IsAtoFChar(value) || Is0to9Char(value))
	
Gc_rc IcePackage::gcHamcSha1(const void *key, size_t keylen,  const void *in, size_t inlen, char *resbuf)
{
	size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
	gcry_md_hd_t mdh;
	unsigned char *hash;
	gpg_error_t err;

        gIceMutex.lock();
	err = gcry_md_open (&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
        
	if (err != GPG_ERR_NO_ERROR)
        {
		    gIceMutex.unlock();
            return GC_INVALID_HASH;
        }
        
 	err = gcry_md_setkey (mdh, key, keylen);
	if (err != GPG_ERR_NO_ERROR)
	{
	  gcry_md_close (mdh);
	  gIceMutex.unlock();
	  return GC_INVALID_HASH;
	}
        
	gcry_md_write (mdh, in, inlen);

	hash = gcry_md_read (mdh, GCRY_MD_SHA1);
	if (hash == NULL)
	{
	  gcry_md_close (mdh);
	  gIceMutex.unlock();
	  return GC_INVALID_HASH;
	}

	memcpy (resbuf, hash, hlen);

	gcry_md_close (mdh);
	gIceMutex.unlock();
	return GC_OK;
}

void IcePackage::iceCrc32Init(int *CRC32)
{
	int i,j;
	unsigned int crc;
	for(i=0; i<ICE_BUFF_LEN/4; i++)
	{
		crc = i;
		for(j=0; j<8; j++)
		{
			if(crc & 1)
			{
				crc = (crc>>1) ^ ICE_CRC32_KEY;
			}
			else
			{
				crc = crc>>1;
			}
		}
		CRC32[i] = crc;
	}

}
unsigned int IcePackage::iceCrc32(unsigned char *buf, int len, int *CRC32)
{
	unsigned int ret = 0xffffffff;
	int i;

	for(i=0; i<len; i++)
	{
		ret = CRC32[((ret & 0xff) ^ buf[i])]^(ret>>8);
	}
	ret = ((~ret)^ICE_CRC32_VALUE);
	return ret;
}

int IcePackage::changeIceUserName(char *source, int size, char *buffer)
{
	char temp[ICE_USERNAME_BASE];
	short type;
	int len=0;
	int alen = 0;
	int offset = 0;
	
	memset(temp, 0, sizeof(temp));
	len+=ICE_HEADER_LEN;
	
	while(len<size)
	{
		memcpy(&type, source+len, ICE_TYPE_LEN);
		len+=ICE_TYPE_LEN;
		type = ntohs(type);

		memcpy(&alen, source+len, ICE_LEN_LEN);
		len+=ICE_LEN_LEN;
		alen = ntohs(alen);
		
		if(type == ICE_TYPE_USERNAME)
		{
			len += alen;
			offset = (alen%ICE_USERNAME_BASE?(ICE_USERNAME_BASE-alen%ICE_USERNAME_BASE):alen%ICE_USERNAME_BASE);

			memcpy(buffer, source, len); 
			memcpy(buffer+len+offset, source+len, size-len);
			memcpy(buffer+len, temp, offset);

			alen = size+offset-ICE_HEADER_LEN;
			alen = htons(alen);
			memcpy(buffer+ICE_LEN_LEN, &alen, ICE_LEN_LEN);
			
			return size+offset;
		}
		else
			len += alen;
	}

	return size;
}
/*Begin Add By Huanghao  Cause: ICE New 2014-12-19:12:59:47*/

/*End Add By Huanghao*/

int IcePackage::addIceTailMI(char *icePasswd, char *source, int size, char *buffer)
{
	int rlen = 0;
	int ret = 0;
	char *passwd = NULL;
	char result[ICE_HEADER_LEN];
	char *ptail = NULL;
	short fakelen = 0;

	rlen = size;
	ptail = &buffer[size];
	memcpy(buffer, source, size);
	memset(result, 0, sizeof(result));
	
	ret = (int)stringprep_profile((char*)icePasswd, &passwd, "SASLprep", (Stringprep_profile_flags)0);
	if(passwd == NULL)
		return size;
	
	fakelen = htons(((short)size+ICE_TYPE_LEN+ICE_LEN_LEN));
	memcpy(buffer+ICE_TYPE_LEN, &fakelen, ICE_LEN_LEN);
	
	gcHamcSha1(passwd, strlen(passwd), buffer, size,  result);
	SET_POINTER_VALUE(ptail, rlen, (unsigned short *), htons, ICE_TYPE_MI, ICE_TYPE_LEN);
	SET_POINTER_VALUE(ptail, rlen, (unsigned short *), htons, ICE_MI_LEN, ICE_LEN_LEN);
	SET_POINTER_BLOCK_VALUE(ptail, rlen, result, ICE_MI_LEN);
        
	free(passwd);

	return rlen;	
}

int IcePackage::addIceTailFP(char *source, int size, char *buffer)
{
	int rlen = 0;
	int ret = 0;
	char *ptail = NULL;
	short fakelen = 0;
	unsigned int CRC32[ICE_BUFF_LEN/4];

	rlen = size;
	ptail = &buffer[size];
	memcpy(buffer, source, size);

	iceCrc32Init((int *)CRC32);
	
	fakelen = htons(((short)size+ICE_TYPE_LEN+ICE_LEN_LEN+ICE_FP_LEN-ICE_HEADER_LEN));
	memcpy(buffer+ICE_LEN_LEN, &fakelen, ICE_LEN_LEN);
	
	ret = iceCrc32((unsigned char *)buffer, rlen, (int*)CRC32);
	SET_POINTER_VALUE(ptail, rlen, (unsigned short *), ntohs, ICE_TYPE_FP, ICE_TYPE_LEN);
	SET_POINTER_VALUE(ptail, rlen, (unsigned short *), ntohs, ICE_FP_LEN, ICE_LEN_LEN);
	SET_POINTER_VALUE(ptail, rlen, (unsigned int *), ntohl, ret, ICE_FP_LEN);

	return rlen;
}

int IcePackage::addIceTail(char *icePasswd, char *source, int size, char *buffer)
{
	if(source == NULL || buffer == NULL || size <= 0 || icePasswd == NULL)
		return size;
	
	size = changeIceUserName(source, size, buffer);
	size = addIceTailMI(icePasswd, buffer, size, buffer);
	size = addIceTailFP(buffer, size, buffer);

	return size;
}

int IcePackage::checkIceCommand(char *buf, char* icepwd)
{
	int command;
	int len;
	int index = 0;

	if(icepwd == NULL)
		return 0;
	
	command = (int)buf[index++];
	if(command != 2)
		return 0;
	
	len = (int)buf[index++];
	if(len <= 0)
	{
		return 0;
	}
	
	for(int j=0; j<len; j++)
	{
		icepwd[j] = buf[index+j];
	}
	
	return 1;
}

/*Begin Add By Huanghao  Cause: ICE New 2014-12-19:13:27:53*/
/*This judgement for FP may cause some problems, but for here is enough*/
int IcePackage::delIceTailMI(char *icePasswd, char *source, int size, char *buffer)
{
	unsigned short mitype = *((unsigned short *)&buffer[size-ICE_LEN_LEN-ICE_TYPE_LEN-ICE_MI_LEN]);
	unsigned short milen = 0;
	unsigned short packlen = 0;

	mitype = ntohs(mitype);
	if(mitype != ICE_TYPE_MI)
	{
		memcpy(buffer, source, size);
		return size;
	}

	milen = *((unsigned short *)&buffer[size-ICE_LEN_LEN-ICE_MI_LEN]);
	milen = ntohs(milen);
	if(milen != ICE_MI_LEN)
	{
		memcpy(buffer, source, size);
		return size;
	}

	size = size-ICE_LEN_LEN-ICE_TYPE_LEN-ICE_MI_LEN;
	memcpy(buffer, source, size);

	packlen = (unsigned short)(size - ICE_HEADER_LEN);
	packlen = htons(packlen);
	memcpy(buffer+ICE_LEN_LEN, &packlen, ICE_LEN_LEN);

	return size;
}

/*This judgment for FP may cause some problems, but for here is enough*/
int IcePackage::delIceTailFP(char *source, int size, char *buffer)
{
	unsigned short fptype = *((unsigned short *)&buffer[size-ICE_LEN_LEN-ICE_TYPE_LEN-ICE_FP_LEN]);
	unsigned short fplen = 0;
	unsigned short packlen = 0;

	fptype = ntohs(fptype);
	if(fptype != ICE_TYPE_FP)
	{
		memcpy(buffer, source, size);
		return size;
	}

	fplen = *((unsigned short *)&buffer[size-ICE_LEN_LEN-ICE_FP_LEN]);
	fplen = ntohs(fplen);
	if(fplen != ICE_FP_LEN)
	{
		memcpy(buffer, source, size);
		return size;
	}

	size = size-ICE_LEN_LEN-ICE_TYPE_LEN-ICE_FP_LEN;
	memcpy(buffer, source, size);
	
	packlen = (unsigned short)(size - ICE_HEADER_LEN);
	packlen = htons(packlen);
	memcpy(buffer+ICE_LEN_LEN, &packlen, ICE_LEN_LEN);

	return size;
}

int IcePackage::deleteIceTail(char *icePasswd, char *source, int size, char *buffer)
{
	if(source == NULL || size < ICE_HEADER_LEN || buffer == NULL)
		return size;

	size = delIceTailFP(source, size, buffer);
	size = delIceTailMI(icePasswd, source, size, buffer);

	return size;
}
bool IcePackage::checkStunMsgTypeAvalid(unsigned short type, short attributeFlag)
{
	int value = 0;
	if(type < Ice_Msg_Req || type >= Ice_Msg_Invalid)
	{
		Printf(NULL, "stun message type is err\r\n");
		return false;
	}
	if(type == Ice_Msg_Req)
	{
		value = (ICE_ATTRIBUTE_XORMAPPEDADDRESS
				  |ICE_ATTRIBUTE_ERRORCODE
				  |ICE_ATTRIBUTE_UNKNOWNATTRI
				);
		Printf(NULL, "stun message type is Req\r\n");
	}
	else if(type == Ice_Msg_Resp)
	{
		value = (ICE_ATTRIBUTE_ICECONTROLLED
				  |ICE_ATTRIBUTE_ICECONTROLLING
				  |ICE_ATTRIBUTE_PRIORITY
				  |ICE_ATTRIBUTE_USECANDIDATE
				  |ICE_ATTRIBUTE_USERNAME
				  |ICE_ATTRIBUTE_ERRORCODE
				  |ICE_ATTRIBUTE_UNKNOWNATTRI
				);
		Printf(NULL, "stun message type is Success Resp\r\n");
	}
	else if(type == Ice_Msg_errResp)
	{
		value = (ICE_ATTRIBUTE_ICECONTROLLED
				  |ICE_ATTRIBUTE_ICECONTROLLING
				  |ICE_ATTRIBUTE_PRIORITY
				  |ICE_ATTRIBUTE_USECANDIDATE
				  |ICE_ATTRIBUTE_USERNAME
				  |ICE_ATTRIBUTE_XORMAPPEDADDRESS
				);
		Printf(NULL, "stun message type is err Resp\r\n");
	}
	else if(type == Ice_Msg_Ind)
	{
		value = (ICE_ATTRIBUTE_ICECONTROLLED
				  |ICE_ATTRIBUTE_ICECONTROLLING
				  |ICE_ATTRIBUTE_PRIORITY
				  |ICE_ATTRIBUTE_USECANDIDATE
				  |ICE_ATTRIBUTE_USERNAME
				  |ICE_ATTRIBUTE_MI
				  |ICE_ATTRIBUTE_XORMAPPEDADDRESS
				  |ICE_ATTRIBUTE_ERRORCODE
				  |ICE_ATTRIBUTE_UNKNOWNATTRI
				);
		Printf(NULL, "stun message type is Ind\r\n");
	}

	Printf(NULL, "Attribute is %d\r\n", attributeFlag);

	if(attributeFlag & value)
	{
		Printf(NULL, "Some attribute is not allowed in the stun message\r\n");
		return false;
	}
	
	return true;
}

int IcePackage::createStunMsgHeader(stStunHeader *pHeader, char *pszResult)
{
	int ret = 0;
	
	SET_POINTER_VALUE(pszResult, ret, (unsigned short *), htons, pHeader->type, (sizeof(short)));
	SET_POINTER_VALUE(pszResult, ret, (unsigned short *), htons, pHeader->length, (sizeof(short)));
	SET_POINTER_VALUE(pszResult, ret, (unsigned int *), htonl, pHeader->magicCookie, (sizeof(int)));
	SET_POINTER_BLOCK_VALUE(pszResult, ret, pHeader->tranID, sizeof(pHeader->tranID));
	
	return ret;
}

int IcePackage::addUserName(char *source, int size, char *userName, int userNameLen, char *buffer)
{
	int ret = size;
	int len = strlen(userName);
	int offset = (ICE_ATTRI_SLIDE - (len % ICE_ATTRI_SLIDE));
	char *ptail;
	memcpy(buffer, source , size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_USERNAME, sizeof(short));
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, len, sizeof(short));
	SET_POINTER_BLOCK_VALUE(ptail, ret, userName, len);

	AddIcePadding(offset, ret, ptail);

	return ret;
}

int IcePackage::addControlling(char *source, int size, char *tieBreaker, char *buffer)
{
	int ret = size;
	char *ptail;
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_CONTROLLING, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, 8, sizeof(short));
	SET_POINTER_BLOCK_VALUE(ptail, ret, tieBreaker, 8);

	return ret;
	
}

int IcePackage::addControlled(char *source, int size, char *tieBreaker, char *buffer)
{
	int ret = size;
	char *ptail;
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_CONTROLLED, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, 8, sizeof(short));
	SET_POINTER_BLOCK_VALUE(ptail, ret, tieBreaker, 8);

	return ret;
}

int IcePackage::addPriority(char *source, int size, unsigned int value, char *buffer)
{
	int ret = size;
	char *ptail;
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_PRIORITY, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, 4, sizeof(short));
	SET_POINTER_VALUE(ptail, ret, (unsigned int *), htonl, value, sizeof(int));

	return ret;
}

int IcePackage::addUseCandidate(char *source, int size, char *buffer)
{
	int ret = size;
	char *ptail;
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_USECANDIDATE, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, 0, sizeof(short));

	return ret;
}

int IcePackage::changePortToX(unsigned short port, unsigned short *xport)
{
	unsigned short key = (ICE_MAGICCOOKIE_VALUE>>16);
	
	if(xport == NULL)
		return 0;

	*xport = (port ^ key);
	*xport = htons(*xport);

	return 1;
}

/*Begin Add By Huanghao  Cause: String IP 2015-1-6:10:42:16*/
/*big-byte*/
unsigned short IcePackage::hexatoi(char *value)
{
	int i=0, j=0;
	unsigned short ret = 0;

	for(i=ICE_IPV6_BYTE_LEN-1, j=ICE_IPV6_BYTE_LEN-1; i>=0; i--, j--)
	{
		if(IsatofChar(value[i]))
			((unsigned char *)(&ret))[j/2] |= ((value[i]-'a'+10)<<((1-j%2)*ICE_IPV6_BYTE_LEN));
		else if(IsAtoFChar(value[i]))
			((unsigned char *)(&ret))[j/2] |= ((value[i]-'A'+10)<<((1-j%2)*ICE_IPV6_BYTE_LEN));
		else if(Is0to9Char(value[i]))
			((unsigned char *)(&ret))[j/2] |= ((value[i]-'0')<<((1-j%2)*ICE_IPV6_BYTE_LEN));
		else
			return ret;
	}
	return ret;
}
int IcePackage::getIpv4Value(unsigned char *value, unsigned char *byteIp)
{
	unsigned char valuet[ICE_IPV6_BUF_MAX_LEN][ICE_IPV6_BYTE_LEN+1] = {{0}};
	memcpy(valuet, value, sizeof(valuet));
	for(int i=0; i<ICE_IPV4_LEN; i++)
	{
		byteIp[i] = (unsigned char)atoi((char *)valuet[i]);
	}

	return ICE_IPV4_LEN;
}

int IcePackage::getIpv6Value(unsigned char *value, int w, int column, char iptype, unsigned char *byteIp)
{
	int index=0;
	int allcol = 0;
	int j = 0, i=0;
	int offset = 0;
	unsigned char *pIp;
	unsigned char valuet[ICE_IPV6_BUF_MAX_LEN][ICE_IPV6_BYTE_LEN+1] = {{0}};

	memcpy(valuet, value, sizeof(valuet));
	if(iptype == ICE_IP_M_TYPE_V6)
		allcol = ICE_IPV6_LEN/2;
	else
	{
		allcol = ICE_IPV6_LEN/2+ICE_IPV4_LEN/2;
		offset = ICE_IPV4_LEN;
	}

	pIp = (unsigned char *)&byteIp[index];
	for(i=0, index=0; i<=column; i++)
	{
		if(i==w)
		{
			for(j=0; j<allcol-column-1; j++)
			{
				SET_POINTER_VALUE(pIp, index,(unsigned short *), (unsigned short), 0, sizeof(short));
			}
		}

		if(iptype == ICE_IP_M_TYPE_V4V6 && i>column-offset)
		{
			SET_POINTER_VALUE(pIp, index,(unsigned char *), atoi, (char *)valuet[i], sizeof(char));
		}
		else
		{
			SET_POINTER_VALUE(pIp, index,(unsigned short *), hexatoi, (char *)valuet[i], sizeof(short));
		}
	}

	return ICE_IPV6_LEN;
}

int IcePackage::changeIPv4ToBIP(unsigned char *strIp, int stateB, int beginP, unsigned char *value, int *column, int *index)
{
	int state = stateB;
	int i=0;
	int stateOne = (*index);
	int stateOPN = 0;

	unsigned char valuet[ICE_IPV6_BUF_MAX_LEN][ICE_IPV6_BYTE_LEN+1]={{0}};
	int columnt=(*column);

	memcpy(valuet, value, sizeof(valuet));

	for(i=beginP; i<(int)strlen((char *)strIp); i++)
	{
		switch(state)
		{
		case ICE_IP_STATE_INIT://B/E
			if(!IsValidIpNumChar(strIp[i]))
				return 0;

			state = ICE_IP_STATE_CHAR;
			valuet[columnt][stateOne++] = strIp[i];

			break;
		case ICE_IP_STATE_CHAR://Char_S
			if(strIp[i] == '.')
			{
				state = ICE_IP_STATE_ONEPOINT;
				stateOne = 0;
				columnt++;
			}
			else if(IsValidIpNumChar(strIp[i]))
			{
				valuet[columnt][stateOne++] = strIp[i];
				state = ICE_IP_STATE_CHAR;

				if(stateOne >= ICE_IPV4_LEN)
					return 0;

			}
			else
				return 0;
			break;
		case ICE_IP_STATE_ONEPOINT://OnePoint_S
			stateOPN++;
			if(stateOPN >= ICE_IPV4_LEN)/*X.X.X.X*/
				return 0;
			
			if(IsValidIpNumChar(strIp[i]))
			{
				state = ICE_IP_STATE_CHAR;

				valuet[columnt][stateOne++] = strIp[i];
			}
			else
				return 0;
			
			break;
		default:
			return 0;
		}
	}

	if(state != ICE_IP_STATE_CHAR || stateOPN != ICE_IPV4_LEN-1)
		return 0;

	memcpy(value, valuet, sizeof(valuet));
	*column = columnt;
	return 1;	
}

int IcePackage::changeStrIP2BIP(unsigned char *strIp, unsigned char *byteIp)
{
	int state = 0;
	int i=0;
	int stateOne = 0;
	int stateFPN = 0;
	int stateTPN = 0;
	unsigned char value[ICE_IPV6_BUF_MAX_LEN][ICE_IPV6_BYTE_LEN+1]={{0}};
	int column=0;
	int w = -1;
	unsigned char iptype = 0;
	int ret = 0;
	
	for(i=0; i<(int)strlen((char *)strIp); i++)
	{
		switch(state)
		{
		case ICE_IP_STATE_INIT://B/E
			if(strIp[i] == ':')
				state = ICE_IP_STATE_TWOPOINT1;
			else if(IsValidIpNumChar(strIp[i]))
			{
				value[column][stateOne] = strIp[i];
				stateOne++;

				state = ICE_IP_STATE_CHAR;
			}
			else
				return 0;
			break;
		case ICE_IP_STATE_TWOPOINT1:// 2p_s
			iptype|=ICE_IP_M_TYPE_V6;

			stateTPN++;
			if(stateTPN >=ICE_IPV6_BYTE_LEN*2)
				return 0;
			
			if(strIp[i] == ':')
				state = ICE_IP_STATE_FOURPOINT;
			else
				return 0;
			break;
		case ICE_IP_STATE_FOURPOINT:// 4p_s
			iptype|=ICE_IP_M_TYPE_V6;
			stateFPN++;
			w = column;

			if(stateFPN > 1)
				return 0;
			
			if(IsValidIpNumChar(strIp[i]))
			{
				value[column][stateOne] = strIp[i];
				stateOne++;
				state = ICE_IP_STATE_CHAR;
			}
			else
				return 0;
			break;
		case ICE_IP_STATE_CHAR:// c_s
			if(IsValidIpNumChar(strIp[i]))
			{
				value[column][stateOne] = strIp[i];

				state = ICE_IP_STATE_CHAR;
				stateOne++;
				if(stateOne > ICE_IPV6_BYTE_LEN)
					return 0;
			}
			else if(strIp[i] == ':')
			{
				state = ICE_IP_STATE_TWOPOINT2;
				stateOne = 0;
				column++;
			}
			else if(strIp[i] == '.')
			{
				iptype|=ICE_IP_M_TYPE_V4;
				stateOne = 0;
				column++;

				ret = changeIPv4ToBIP(strIp, ICE_IP_STATE_ONEPOINT, i+1, (unsigned char*)value, &column, &stateOne);
				if(ret == 0)
					return 0;
				i = strlen((char *)strIp);
			}
			else
				return 0;
			break;
		case ICE_IP_STATE_TWOPOINT2:// 2p_s2
			iptype|=ICE_IP_M_TYPE_V6;

			stateTPN++;
			if(stateTPN >=ICE_IPV6_BYTE_LEN*2)
				return 0;

			if(strIp[i] == ':')
				state = ICE_IP_STATE_FOURPOINT;
			else if(IsValidIpNumChar(strIp[i]))
			{
				value[column][stateOne] = strIp[i];
				stateOne++;

				state = ICE_IP_STATE_CHAR;
			}
			else
				return 0;
			break;	
		default:
			return 0;
		}
	}

	if(state != ICE_IP_STATE_CHAR)
		return 0;

	if(iptype == ICE_IP_M_TYPE_V4)
	{	
		ret = getIpv4Value((unsigned char *)value, byteIp);
	}
	else
	{
		if(w==-1 && stateTPN != ICE_IPV6_LEN/2-1 && iptype == ICE_IP_M_TYPE_V6)
			return 0;
		else if(w==-1 && stateTPN != ICE_IPV6_LEN/2-2 && iptype == ICE_IP_M_TYPE_V4V6)
			return 0;
		
		ret = getIpv6Value((unsigned char *)value, w, column, iptype,byteIp);	
	}
	
	return ret;
}

int IcePackage::changeStrIpv4AddressToX(unsigned char *strIp, unsigned int *xip)
{
	unsigned int ipt = 0;
	if(strIp == NULL || xip == NULL)
		return 0;

	if(!changeStrIP2BIP(strIp,(unsigned char *)&ipt))
	{
		Printf(NULL, "the ip(%s) can't be changed, please check it\r\n", strIp);
		return 0;
	}

	Printf(NULL, "the old ip: %s\r\n", strIp);
	Printf(NULL, "get the bIp %x\r\n", htonl(ipt));
	return changeIpv4AddressToX(ntohl(ipt), xip);
}

int IcePackage::changeStrIpv6AddressToX(unsigned char *strIp, unsigned char *transID, unsigned char *xip)
{
	unsigned char byteIp[ICE_IPV6_LEN] = {0};
	
	if(strIp == NULL || xip == NULL || transID == NULL)
		return 0;

	if(!changeStrIP2BIP(strIp,(unsigned char *)byteIp))
	{
		Printf(NULL, "the ip(%s) can't be changed, please check it\r\n", strIp);
		return 0;
	}

	Printf(NULL, "the old ip: %s\r\n", strIp);
	StunLogBlock(NULL, byteIp, ICE_IPV6_LEN, "the changed IPv6:");
	return changeIpv6AddressToX((unsigned char *) byteIp, transID, xip);
}

/*End Add By Huanghao*/
int IcePackage::changeIpv4AddressToX(unsigned int ip, unsigned int *xip)
{
	unsigned int key = ICE_MAGICCOOKIE_VALUE;
	if(xip == NULL)
		return 0;

	*xip = (ip ^ key);
	*xip = htonl(*xip);

	return 1;
}

int IcePackage::generateRandNum(unsigned char *buff, int len)
{
	int i;

	srand((unsigned) time(NULL ));
	if((buff==NULL) || (len<=0))
		return 0;

	for(i=0; i<len; i++)
		buff[i] = rand()%(0xff);
	return 1;
}

int IcePackage::changeIpv6AddressToX(unsigned char *byteIp, unsigned char *transID, unsigned char *xip)
{
	unsigned char key[ICE_IPV6_LEN];

	if(byteIp== NULL || transID == NULL || xip == NULL)
		return 0;

	key[0] = 0x21;
	key[1] = 0x12;
	key[2] = 0xa4;
	key[3] = 0x42;
	memcpy(&key[4], transID, ICE_TRANSID_LEN);

	for(int i=0; i<ICE_IPV6_LEN; i++)
	{
		xip[i] = (key[i]^byteIp[i]);
	}

	return 1;
}

int IcePackage::addErroCode(char *source, int size, stERRORCODE *pstEC, char *buffer)
{
	int ret = size;
	char *ptail; 
	unsigned char value = 0;
	int len = (strlen(pstEC->reasonPhrase)+5);
	int offset = (ICE_ATTRI_SLIDE - len%ICE_ATTRI_SLIDE);
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	value = (pstEC->Reserved2<<3);
	value |= pstEC->mClass;

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_ERRORCODE, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, len, sizeof(short));
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, pstEC->Reserved1, sizeof(short));
	SET_POINTER_VALUE(ptail, ret, (unsigned char *), (unsigned char), value, sizeof(char));
	SET_POINTER_VALUE(ptail, ret, (unsigned char *), (unsigned char), pstEC->number, sizeof(char));
	SET_POINTER_BLOCK_VALUE(ptail, ret, (char *)pstEC->reasonPhrase, strlen(pstEC->reasonPhrase)+1);

	AddIcePadding(offset, ret, ptail);

	return ret;
}

int IcePackage::addUnknownAttri(char *source, int size, stUNKNOWNATTRIBUTES *pstUA, char *buffer)
{
	int ret = size;
	char *ptail;
	int len  = pstUA->typeNum * 2;
	int offset = (ICE_ATTRI_SLIDE - len%ICE_ATTRI_SLIDE);
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_UNKNOWNATTRIBUTES, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, len, sizeof(short));
	for(int i=0; i<pstUA->typeNum; i++)
		SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, pstUA->type[i], sizeof(short));

	AddIcePadding(offset, ret, ptail);
	return ret;
}

int IcePackage::addXorMapAddress(char *source, int size, stXORMAPADDRESS *pstXMA, char *buffer)
{
	int ret = size;
	char *ptail;
	int len;
	memcpy(buffer, source, size);
	ptail = &buffer[size];

	if(pstXMA->family == 0x01)
		len = ICE_IPV4_LEN+ICE_TYPE_LEN+ICE_LEN_LEN;
	else
		len = ICE_IPV6_LEN+ICE_TYPE_LEN+ICE_LEN_LEN;

	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, ICE_TYPE_XORMAPPEDADDRESS, sizeof(short));	
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), htons, len, sizeof(short));
	SET_POINTER_VALUE(ptail, ret, (char *), (char), pstXMA->flag, sizeof(char));
	SET_POINTER_VALUE(ptail, ret, (char *), (char), pstXMA->family, sizeof(char));
	SET_POINTER_VALUE(ptail, ret, (unsigned short *), (unsigned short), pstXMA->xport, sizeof(short));
	if(pstXMA->family == 0x01)
		SET_POINTER_VALUE(ptail, ret, (unsigned int *), (unsigned int), pstXMA->ipv4xaddress, sizeof(int));
	else
		SET_POINTER_BLOCK_VALUE(ptail,ret, (char *)pstXMA->ipv6xaddress, len-ICE_TYPE_LEN-ICE_LEN_LEN);
	
	return ret;
}

int IcePackage::createStunMsgReq(stStunMsg *stMsg, char *pszResult)
{
	int ret = 0;
	ret = createStunMsgHeader(&stMsg->header, pszResult);
	ret = addUserName(pszResult, ret, (char *)stMsg->Req.userName, strlen(stMsg->Req.userName), pszResult);
	if(stMsg->attriFlag & ICE_ATTRIBUTE_ICECONTROLLING)
	{
		ret = addControlling(pszResult, ret, (char *)stMsg->Req.iceControlling, pszResult);
	}
	else
	{
		ret = addControlled(pszResult, ret, (char *)stMsg->Req.iceControlled, pszResult);
	}

	if(stMsg->attriFlag & ICE_ATTRIBUTE_USECANDIDATE)
	{
		ret = addUseCandidate(pszResult, ret, pszResult);
	}

	ret = addPriority(pszResult, ret, stMsg->Req.priority, pszResult);
	ret = addIceTailMI((char *)stMsg->remotePwd, pszResult, ret, pszResult);
	ret = addIceTailFP(pszResult, ret, pszResult);

	StunLogBlock(NULL, (unsigned char*)pszResult, ret, "Req");

	return ret;
}

int IcePackage::createStunMsgResp(stStunMsg *stMsg, char *pszResult)
{
	int ret = 0;
	ret = createStunMsgHeader(&stMsg->header, pszResult);

	ret = addXorMapAddress(pszResult, ret, &stMsg->Resp.xorMapAddress, pszResult);
	ret = addIceTailMI((char *)stMsg->remotePwd, pszResult, ret, pszResult);
	ret = addIceTailFP(pszResult, ret, pszResult);
	
	StunLogBlock(NULL, (unsigned char*)pszResult, ret, "Success Resp");

	return ret;
}
int IcePackage::createStunMsgErrResp(stStunMsg *stMsg, char *pszResult)
{
	int ret = 0;
	ret = createStunMsgHeader(&stMsg->header, pszResult);
	ret = addErroCode(pszResult, ret, &stMsg->ErrResp.errorCode, pszResult);
	if(stMsg->ErrResp.errorCode.number == 20 && stMsg->ErrResp.errorCode.mClass == 4)
		ret = addUnknownAttri(pszResult, ret, &stMsg->ErrResp.unknownAttributes, pszResult);

	ret = addIceTailFP(pszResult, ret, pszResult);
	
	StunLogBlock(NULL, (unsigned char*)pszResult, ret, "Error Resp");
	return ret;
}

int IcePackage::createStunMsgInd(stStunMsg *stMsg, char *pszResult)
{
	int ret = 0;
	ret = createStunMsgHeader(&stMsg->header, pszResult);
	//ret = addIceTailMI((char *)stMsg->remotePwd, pszResult, ret, pszResult);
	ret = addIceTailFP(pszResult, ret, pszResult);

	StunLogBlock(NULL, (unsigned char*)pszResult, ret, "Ind");
	return ret;
}

int IcePackage::createStunMessage(stStunMsg *stMsg, char *pszResult)
{
	if((stMsg == NULL) || (pszResult == NULL))
		return 0;
	
	if(!checkStunMsgTypeAvalid(stMsg->header.type, stMsg->attriFlag))
		return 0;
	
	if(stMsg->header.type == Ice_Msg_Req)
	{
		return createStunMsgReq(stMsg, pszResult);
	}
	else if(stMsg->header.type == Ice_Msg_Resp)
	{
		return createStunMsgResp(stMsg, pszResult);
	}
	else if(stMsg->header.type == Ice_Msg_errResp)
	{
		return createStunMsgErrResp(stMsg, pszResult);
	}
	else if(stMsg->header.type == Ice_Msg_Ind)
	{
		return createStunMsgInd(stMsg, pszResult);
	}

	return 0;
}

bool IcePackage::checkIfStunMsg(char *source, int size)
{
	unsigned char vtemp = 0;
	unsigned int vitemp = 0;
	char *psTemp = source;

	if(source == NULL)
		return false;
	
	if(size < ICE_HEADER_LEN)
	{
		Printf(NULL, "stun: the length is to short\r\n");
		return false;
	}
	
	vtemp = *((unsigned char *)psTemp);
	if(vtemp & 0xc0)
	{
		Printf(NULL, "stun:the flag is not 00\r\n");
		return false;
	}
	
	memcpy(&vitemp, psTemp+ICE_TYPE_LEN+ICE_LEN_LEN, sizeof(int));
	vitemp = ntohl(vitemp);
	if(vitemp != ICE_MAGICCOOKIE_VALUE)
	{
		Printf(NULL, "stun:the MagicCookie is not right\r\n");
		return false;
	}

	return true;
}

bool IcePackage::decodeStunMessage(char *source, int size, stStunMsg *poutStunMsg, int *errCode)
{
	
	if(source == NULL || size == 0 || poutStunMsg == NULL)
	{
		ICE_SET_ERROR_CODE(ICE_ERR_PARAMETER_ERR, errCode)
		return false;
	}

	if(!checkIfStunMsg(source, size))
	{
		ICE_SET_ERROR_CODE(ICE_ERR_NOT_STUNMSG, errCode)
		return false;
	}
	
	/*now, we need not to decode the Message*/
	ICE_SET_ERROR_CODE(ICE_SUCCESS, errCode)
	return true;
}

int IcePackage::hexatob(char *value, int size, char *result)
{
    int i=0, j=0, k=0;
    if(value == NULL || result == NULL || size <=0)
        return 0;

    memset(result, 0, size/2+(size%2));
    k = size+size%2;

	for(i=size; i>0; i--)
    {
        j = (j+1)%2;
        if(IsatofChar(value[i-1]))
            result[(k-1)/2] |= ((value[i-1]-'a'+10)<<((1-j%2)*ICE_IPV6_BYTE_LEN));
        else if(IsAtoFChar(value[i-1]))
            result[(k-1)/2] |= ((value[i-1]-'A'+10)<<((1-j%2)*ICE_IPV6_BYTE_LEN));
        else if(Is0to9Char(value[i-1]))
            result[(k-1)/2] |= ((value[i-1]-'0')<<((1-j%2)*ICE_IPV6_BYTE_LEN));
        else
            return 0;

    }

    return size/2+(size%2);
}
/*End Add By Huanghao*/
